package com.lzs.common.utils;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URL;
import java.util.Enumeration;

/**
 * FileName: IPUtils
 * <p>
 * <p>
 * <p>
 * Description:
 *
 * @author lzs
 * @version 1.0.0
 * @create 2020/1/12 11:16
 */
@Slf4j
public class IPUtils {

    private static volatile InetAddress LOCAL_ADDRESS = null;
    /**
     * 获取IP地址
     * 使用Nginx等反向代理软件， 则不能通过request.getRemoteAddr()获取IP地址
     * 如果使用了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP地址，X-Forwarded-For中第一个非unknown的有效IP字符串，则为真实IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = null;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } catch (Exception e) {
            log.error("IPUtils ERROR ", e);
        }
        //使用代理，则获取第一个IP地址
        if(StringUtils.isEmpty(ip) && ip.length() > 15) {
			if(ip.indexOf(",") > 0) {
				ip = ip.substring(0, ip.indexOf(","));
			}
		}
        return ip;
    }
    /**
     * get ip
     *
     * @return
     */
    public static String getIp() {
        InetAddress address = getAddress();
        if (address == null) {
            return null;
        }
        return address.getHostAddress();
    }
    /**
     * get address
     *
     * @return
     */
    private static InetAddress getAddress() {
        if (LOCAL_ADDRESS != null) {
            return LOCAL_ADDRESS;
        }
        InetAddress localAddress = getFirstValidAddress();
        LOCAL_ADDRESS = localAddress;
        return localAddress;
    }
    /**
     * get first valid addredd
     *
     * @return
     */
    private static InetAddress getFirstValidAddress() {
        InetAddress localAddress = null;
        try {
            localAddress = InetAddress.getLocalHost();
            if (!localAddress.isLoopbackAddress() && !localAddress.isLinkLocalAddress()
                    && localAddress.isSiteLocalAddress()) {
                return localAddress;
            }
        } catch (Throwable e) {
            log.error("Failed to retriving ip address, " + e.getMessage(), e);
        }
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            if (interfaces != null) {
                while (interfaces.hasMoreElements()) {
                    try {
                        NetworkInterface network = interfaces.nextElement();
                        Enumeration<InetAddress> addresses = network.getInetAddresses();
                        while (addresses.hasMoreElements()) {
                            try {
                                InetAddress address = addresses.nextElement();
                                if (!address.isLoopbackAddress()
                                        && !address.isLinkLocalAddress()
                                        && address.isSiteLocalAddress()) {
                                    return address;
                                }
                            } catch (Throwable e) {
                                log.error(
                                        "Failed to retriving ip address, " + e.getMessage(), e);
                            }
                        }
                    } catch (Throwable e) {
                        log.error("Failed to retriving ip address, " + e.getMessage(), e);
                    }
                }
            }
        } catch (Throwable e) {
            log.error("Failed to retriving ip address, " + e.getMessage(), e);
        }
        log.error("Could not get local host ip address, will use 127.0.0.1 instead.");
        return localAddress;
    }
    /**
     *@创建人:  lzs
     *@创建时间:  2020/2/10 17:06
     *@描述:  获取代理的地址
     *@参数: 
     *@返回值: 
     */
    public static String getAgentAddr(HttpServletRequest request){
        String ip = request.getHeader("x-forwarded-for");
        if (StringUtils.isEmpty(ip) || StringUtils.equalsIgnoreCase("unknown",ip)){
            return null;
        }
        String addr = "";
        // 此时是有代理的
        if (StringUtils.contains(ip,",")){
            addr = StringUtils.substring(ip,ip.indexOf(",")+1);
            return StringUtils.join(addr,",",request.getRemoteAddr());
        }
        return request.getRemoteAddr();
    }


//    public static void main(String[] args) throws Exception {
//        String addr = getAddress("ip=113.129.115.92","UTF-8");
//        System.out.println(addr);
//    }

    /**
     * 获取地址
     * @param params
     * @param encoding
     * @return
     * @throws Exception
     */
    public static String getAddress(String params, String encoding) throws Exception{
        String path = "http://ip.taobao.com/service/getIpInfo.php";
        String returnStr = getRs(path, params, encoding);
        JSONObject json=null;
        if(returnStr != null){
            json = JSONObject.parseObject(returnStr);
            if("0".equals(json.get("code").toString())){
                StringBuffer buffer = new StringBuffer();
                //buffer.append(decodeUnicode(json.optJSONObject("data").getString("country")));//国家
                //buffer.append(decodeUnicode(json.optJSONObject("data").getString("area")));//地区
                String region = decodeUnicode(json.getJSONObject("data").getString("region"));
                buffer.append(region);//省份
                // 判断是否是直辖市 如果是直辖市的话拼接的是市
                if (StringUtils.equals(region,"北京")
                        || StringUtils.equals(region,"天津")
                        || StringUtils.equals(region,"重庆")
                        || StringUtils.equals(region,"上海")){
                    buffer.append("市");
                } else {
                    buffer.append("省");
                }
                buffer.append("/");
                buffer.append(decodeUnicode(json.getJSONObject("data").getString("city")));//市区
                buffer.append("市");
                buffer.append("/");
//                buffer.append(decodeUnicode(json.optJSONObject("data").getString("county")));//地区
//                buffer.append(decodeUnicode(json.optJSONObject("data").getString("isp")));//ISP公司
                String address = buffer.toString();
                // 去除掉所有的X
                address = StringUtils.replace(address,"X","");
                log.info("获取到的IP地址是==>[{}]",address);
                return address;
            }else{
                return "获取地址失败?";
            }
        }
        return null;
    }


    /**
     * 从url获取结果
     * @param path
     * @param params
     * @param encoding
     * @return
     */
    public static String getRs(String path, String params, String encoding){
        URL url = null;
        HttpURLConnection connection = null;
        try {
            url = new URL(path);
            connection = (HttpURLConnection)url.openConnection();// 新建连接实例
            connection.setConnectTimeout(2000);// 设置连接超时时间，单位毫�?
            connection.setReadTimeout(2000);// 设置读取数据超时时间，单位毫�?
            connection.setDoInput(true);// 是否打开输出�? true|false
            connection.setDoOutput(true);// 是否打开输入流true|false
            connection.setRequestMethod("POST");// 提交方法POST|GET
            connection.setUseCaches(false);// 是否缓存true|false
            connection.connect();// 打开连接端口
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            out.writeBytes(params);
            out.flush();
            out.close();
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),encoding));
            StringBuffer buffer = new StringBuffer();
            String line = "";
            while ((line = reader.readLine())!= null) {
                buffer.append(line);
            }
            reader.close();
            return buffer.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            connection.disconnect();// 关闭连接
        }
        return null;
    }
    /**
     * 字符转码
     * @param theString
     * @return
     */
    public static String decodeUnicode(String theString){
        char aChar;
        int len = theString.length();
        StringBuffer buffer = new StringBuffer(len);
        for (int i = 0; i < len;) {
            aChar = theString.charAt(i++);
            if(aChar == '\\'){
                aChar = theString.charAt(i++);
                if(aChar == 'u'){
                    int val = 0;
                    for(int j = 0; j < 4; j++){
                        aChar = theString.charAt(i++);
                        switch (aChar) {
                            case '0':
                            case '1':
                            case '2':
                            case '3':
                            case '4':
                            case '5':
                            case '6':
                            case '7':
                            case '8':
                            case '9':
                                val = (val << 4) + aChar - '0';
                                break;
                            case 'a':
                            case 'b':
                            case 'c':
                            case 'd':
                            case 'e':
                            case 'f':
                                val = (val << 4) + 10 + aChar - 'a';
                                break;
                            case 'A':
                            case 'B':
                            case 'C':
                            case 'D':
                            case 'E':
                            case 'F':
                                val = (val << 4) + 10 + aChar - 'A';
                                break;
                            default:
                                throw new IllegalArgumentException(
                                        "Malformed      encoding.");
                        }
                    }
                    buffer.append((char) val);
                }else{
                    if(aChar == 't'){
                        aChar = '\t';
                    }
                    if(aChar == 'r'){
                        aChar = '\r';
                    }
                    if(aChar == 'n'){
                        aChar = '\n';
                    }
                    if(aChar == 'f'){
                        aChar = '\f';
                    }
                    buffer.append(aChar);
                }
            }else{
                buffer.append(aChar);
            }
        }
        return buffer.toString();
    }









}
